package accounts

import (
	"fmt"
	"github.com/shopspring/decimal"
	"github.com/sirupsen/logrus"
	"github.com/tietang/dbx"
)

// 数据访问层(负责持久化数据)

type AccountDao struct {
	runner *dbx.TxRunner // 事务对象
}

// 查询数据库持久化对象的单实例(获取单条记录)
func (dao *AccountDao)GetOne(accountNo string) *Account{
	data := &Account{
		AccountNo: accountNo, // 需要一个唯一索引的字段
	}
	ok, err := dao.runner.GetOne(data)
	if err != nil{
		logrus.Error(err)
		return nil
	}
	if !ok{
		logrus.Warn(fmt.Sprintf("accountNo:[%s]的记录不存在", accountNo))
		return nil
	}
	return data
}

// 通过用户id和账户类型来查询账户信息
func (dao *AccountDao) GetByUserId(userId string, accountType int) *Account{
	data := &Account{}
	sql := "select * from account where user_id = ? and account_type = ?"
	ok, err := dao.runner.Get(data, sql, userId, accountType)
	if err != nil{
		logrus.Error(err)
		return nil
	}
	if !ok{
		logrus.Warn(fmt.Sprintf("userId:[%s]的账户类型为[%d]记录不存在", userId, accountType))
		return nil
	}
	return data
}

// 账户数据的插入
func (dao *AccountDao) Insert(account *Account) (id int64, err error){
	rs, err := dao.runner.Insert(account)
	if err != nil{
		return 0, err
	}
	return rs.LastInsertId()
}

// 账户余额的更新
// amount: 负数:支出 正数:收入
func (dao *AccountDao) UpdateBalance(accountNo string, amount decimal.Decimal) (rows int64, err error){
	sql := "update account set " +
		"balance = balance + cast(? as decimal(30, 6)) " +
		"where account_no = ? and balance >= -1 * cast(? as decimal(30, 6))"
	// balance >= -1 * cast(? as decimal(30, 6)) (乐观锁的实现)
	// 如果amount为正数(收入), 乘以-1 变成 负数, 而balance是恒大于等于0的,所以条件成立
	// 如果amount为负数(支出), 乘以-1 变成 正数, 那么只有 balance 大于这个数才可递减
	rs, err := dao.runner.Exec(sql, amount.String(), accountNo, amount.String())
	if err != nil{
		return 0, err
	}
	return rs.RowsAffected()
}

// 账户状态更新
func (dao *AccountDao) UpdateStatus(accountNo string, status int) (rows int64, err error){
	sql := "update account set status = ? where account_no = ?"
	rs, err := dao.runner.Exec(sql, status, accountNo)
	if err != nil{
		return 0, err
	}
	return rs.RowsAffected()
}
